/*
 * @(#)WorkflowPermissionManager.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.workflow.core;

import java.sql.Connection;
import java.util.Hashtable;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.dcivision.framework.ApplicationException;
import com.dcivision.framework.DataSourceFactory;
import com.dcivision.framework.ErrorConstant;
import com.dcivision.framework.GlobalConstant;
import com.dcivision.framework.PermissionManager;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.TextUtility;
import com.dcivision.framework.Utility;
import com.dcivision.user.bean.UserGroup;
import com.dcivision.user.bean.UserRole;
import com.dcivision.user.dao.MtmUserRecordUserGroupDAObject;
import com.dcivision.user.dao.MtmUserRecordUserRoleDAObject;
import com.dcivision.user.dao.UserGroupDAObject;
import com.dcivision.user.dao.UserRoleDAObject;
import com.dcivision.workflow.bean.MtmWorkflowChildParentProgress;
import com.dcivision.workflow.bean.MtmWorkflowDynamicUserActor;
import com.dcivision.workflow.bean.MtmWorkflowStepUserActor;
import com.dcivision.workflow.bean.WorkflowProgress;
import com.dcivision.workflow.bean.WorkflowRecord;
import com.dcivision.workflow.bean.WorkflowStep;
import com.dcivision.workflow.dao.MtmWorkflowChildParentProgressDAObject;
import com.dcivision.workflow.dao.MtmWorkflowDynamicUserActorDAObject;
import com.dcivision.workflow.dao.MtmWorkflowStepUserActorDAObject;
import com.dcivision.workflow.dao.WorkflowProgressDAObject;
import com.dcivision.workflow.dao.WorkflowRecordDAObject;
import com.dcivision.workflow.dao.WorkflowStepDAObject;
/**
 * WorkflowPermissionManager.java
 * 
 * This class is use to determine the permission a specific user has against 
 * a specific workflow step
 * 
 * @company DCIVision Limited
 * @version $Revision: 1.18 $
 */
public class WorkflowPermissionManager extends PermissionManager {
  public static final String REVISION = "$Revision: 1.18 $";
  
  //set for workflow user to provide all rights
  private final static String ALL_RIGHTS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  
  public static final String DENIED_READ_PERMISSION = "r";
  private SessionContainer sessionContainer = null;
  private Connection dbConn = null;
  private Hashtable permissionCache = new Hashtable();
  
  protected Log log = LogFactory.getLog(this.getClass().getName());
  
  
  // static variable
  private final static Hashtable hAdminFunction = new Hashtable();
  
  /**
   * Constructor
   * 
   * @param sessionContainer
   */
  public WorkflowPermissionManager(SessionContainer sessionContainer, Connection dbConn) {
    super(sessionContainer);
    this.sessionContainer = sessionContainer;
    this.dbConn = dbConn;
  }
  /**
   * Determine the permission a specific user has against a specific workflow step
   * 
   * @param sObjectType
   * @param nObjectID
   * @param sRight
   * @return boolean
   *  @throws ApplicationException
   */
  public synchronized boolean hasAccessRight(String sObjectType, Integer nObjectID, String sRight) throws ApplicationException {
    String permission = this.getPermission(sObjectType, nObjectID);
    
    if (Utility.isEmpty(permission)) {
      return(false);
    } else if ("*".equals(sRight)){
      return this.checkHavePermission(permission);
    } else {
      return(permission.indexOf(sRight) >= 0);
    }
  }
  /**
   * Determine the permission a specific user has against a specific workflow step
   * 
   * @param sObjectType The string of object type
   * @param wfProgress The object of WorkflowProgress
   * @param sRight
   * @param userRecordID The integer of user record ID
   * @return boolean
   * @throws ApplicationException
   */
  public synchronized boolean hasAccessRight(String sObjectType, WorkflowProgress wfProgress, String sRight, Integer userRecordID) throws ApplicationException {
    return  hasAccessRight(sObjectType,wfProgress.getWorkflowStepID(), wfProgress.getTrackID(), sRight, userRecordID);
  }
  /**
   * Determine the permission a specific user has against a specific workflow step
   * 
   * @param sObjectType The string of object type
   * @param workflowStepID The integer of workflow step ID
   * @param workflowTrackID The integer of workflow track ID
   * @param sRight
   * @param userRecordID The integer of user record ID
   * @return boolean
   * @throws ApplicationException
   */
  public synchronized boolean hasAccessRight(String sObjectType, Integer workflowStepID, Integer workflowTrackID, String sRight, Integer userRecordID) throws ApplicationException {
    String permission = null;
    if (!Utility.isEmpty(userRecordID)) {
      permission = this.getPermission((Connection)null, sObjectType, workflowStepID, workflowTrackID, userRecordID); 
    } else {
      permission = this.getPermission((Connection)null, sObjectType, workflowStepID, workflowTrackID);
    }
    
    if (Utility.isEmpty(permission)) {
      return(false);
    } else if ("*".equals(sRight)){
      return this.checkHavePermission(permission);
    } else {
      return(permission.indexOf(sRight) >= 0);
    }
  }
  /**
   * Gets a string of user's permission
   * 
   * @param dbConn The database conncetion
   * @param objectType The object type
   * @param objectID The object ID
   * @param trackID The track ID
   * @param userRecordID The user record ID
   * @return String of user's permission
   * @throws ApplicationException
   */
  public synchronized String getPermission(Connection dbConn, String objectType, Integer objectID, Integer trackID, Integer userRecordID) throws ApplicationException {
    String result = "";
    Connection conn = null;
    boolean matchRequiredFlag = true;
    try {
      if (dbConn == null) {
        conn = DataSourceFactory.getConnection();
      } else {
        conn = dbConn;
      }
      String permissionString = null;
      if (!Utility.isEmpty(userRecordID)) {
        permissionString = this.getPermissionString(conn, objectType, objectID, trackID, userRecordID);
      } else {
        permissionString = this.getPermissionString(conn, objectType, objectID, trackID);
      }
      log.info("Object Permission ("+objectType+objectID+"):" + permissionString);
      return (TextUtility.noNull(permissionString));
    } catch (ApplicationException appEx) {
      throw appEx;
    } catch (Exception e) {
      log.error(e, e);
      throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
    } finally {
      if (dbConn == null) {
        try { conn.close(); } catch (Exception ignore) {} finally { conn = null; }
      } else {
        conn = null;
      }
    }
  }
  /**
   * Gets a string of user's permission
   * 
   * @param dbConn The database conncetion
   * @param objectType The object type
   * @param objectID The object ID
   * @param trackID The track ID
   * @return string
   * @throws ApplicationException
   */
  public synchronized String getPermission(Connection dbConn, String objectType, Integer objectID, Integer trackID) throws ApplicationException {
    return getPermission(dbConn, objectType, objectID, trackID, null);
  }
  /**
   * Gets a string of the user permission for given workflow step,workflow track and user record
   * 
   * @param conn The database connection
   * @param objectType The object type
   * @param objectID The object ID
   * @return string of the user permission
   * @throws ApplicationException
   * @see com.dcivision.framework.PermissionManager#DENIED_READ_PERMISSION
   */
  protected synchronized String getPermissionString(Connection conn, String objectType, Integer objectID) throws ApplicationException {
    String result = "";
    boolean matchRequiredFlag = true;
    
    if(this.sessionContainer.getByPassPermission()){
      return WorkflowPermissionManager.ALL_RIGHTS;
    } else {
      
      if (this.permissionCache.get(objectType + objectID)!=null) {
        return((String)this.permissionCache.get(objectType + objectID));
      }
      
      try {
        if (!this.isMatchRequired(conn, objectType, objectID)) {
          matchRequiredFlag = false;
          result = PermissionManager.DENIED_READ_PERMISSION;
        } else {
          // result = this.getPermissionForUser(objectID, null, this.sessionContainer.getUserRecordID());
          result = this.getUserPermission4SpecialTask(objectID, null, this.sessionContainer.getUserRecordID());
          log.debug("The Permission [" + objectType + "::" + objectID + "]     " + result);
        }
        if(!Utility.isEmpty(result)){
          this.permissionCache.put(objectType + objectID, result);
        }
        return result;
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      }
    }//end workflow check
  }
  /**
   * Gets a string of the user permission for given workflow step,workflow track and user record
   * 
   * @param conn The database connection
   * @param objectType The object type
   * @param objectID The object ID
   * @param trackID The workflow track ID
   * @param userRecordID The user record ID
   * @return string of the user permission
   * @throws ApplicationException
   */
  protected synchronized String getPermissionString(Connection conn, String objectType, Integer objectID, Integer trackID, Integer userRecordID) throws ApplicationException {
    String result = "";
    boolean matchRequiredFlag = true;
    
    if(this.sessionContainer.getByPassPermission()){
      return WorkflowPermissionManager.ALL_RIGHTS;
    } else {
      
      if (this.permissionCache.get(objectType + objectID)!=null) {
        return((String)this.permissionCache.get(objectType + objectID));
      }
      try {
        if (!this.isMatchRequired(conn, objectType, objectID)) {
          matchRequiredFlag = false;
          result = PermissionManager.DENIED_READ_PERMISSION;
        } else {
          if (!Utility.isEmpty(userRecordID)) {
            // result = this.getPermissionForUser(objectID, trackID, userRecordID);
            result = this.getUserPermission4SpecialTask(objectID, trackID, userRecordID);
          } else {
            // result = this.getPermissionForUser(objectID, trackID, this.sessionContainer.getUserRecordID());
            result = this.getUserPermission4SpecialTask(objectID, trackID, this.sessionContainer.getUserRecordID());
          }
          log.debug("The Permission [" + objectType + "::" + objectID + "]     " + result);
        }
        if(!Utility.isEmpty(result)){
          this.permissionCache.put(objectType + objectID, result);
        }
        return result;
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      }
    }//end workflow check
  }
  /**
   * Gets a string of the user permission for given workflow step,workflow track and user record
   * 
   * @param conn The database conncetion
   * @param objectType The object type
   * @param objectID The object ID
   * @param trackID The workflow track ID
   * @return string of the user permission
   * @throws ApplicationException
   */
  protected synchronized String getPermissionString(Connection conn, String objectType, Integer objectID, Integer trackID) throws ApplicationException {
    return getPermissionString(conn,  objectType,  objectID, trackID, null);   
  }
  /**
   * Checks if the current user has the given permission 
   * 
   * @param permissionTypes The permission type
   * @return boolean
   * @throws ApplicationException
   */
  public boolean checkHavePermission(String permissionTypes) throws ApplicationException {
    for (int i = 0; i <permissionTypes.length(); i++) {
      if (WorkflowPermissionManager.ALL_RIGHTS.indexOf(permissionTypes.substring(i, i+1)) >= 0 ) {
        return true;
      } else {
        continue;
      }
    }
    return false;
  }
  
  /**
   * Merge the permission value into a text string.
   * 
   * If there are same type of permission, 'DENY' type is priority.
   * 
   * Example
   * target = "RW"
   * source = "Rw"
   * 
   * result to return = "Rw"
   * 
   * @param target a text of permission value
   * @param source the permission value add to target
   * @return a text string contain the permission value merge target and source.
   *         a null value will return if given target and source all are null.
   */
  protected String mergePermissionValue(String target, String source) {
    
    // Return null if target and source all are null.
    if (target == null && source == null) {
      return (null);
    }
    
    String values = null;
    String mergeValues = ""; // The result value to return.
    
    if (target != null && source != null) {
      values = target + source;
    }

    if (source == null) {
      values = target;
    }
    
    if (target == null) {
      values = source;
    }
    
    String denyValues = "";
    
    // Phase 1 : Found out the 'DENY' values first.
    for (int i = 0; i < values.length(); i++) {
      char ch = values.charAt(i);
      if (
          Character.isLowerCase(ch) // 'DENY' value.
          && denyValues.indexOf(ch) < 0 // Not repeat.
          ) {
        denyValues += ch;
      }
    }
    
    // Phase 2 : Record all of the 'DENY'
    mergeValues = new String(denyValues);
    
    // Phase 3 : Record 'ALLOW' value, If there are same type of permission,
    // 'DENY' type is priority, ignore the 'ALLOW' value.
    for (int i = 0; i < values.length(); i++) {
      char ch = values.charAt(i);
      if (
          Character.isUpperCase(ch) // 'ALLOW' value.
          && denyValues.indexOf(Character.toLowerCase(ch)) < 0 // Not contain 'DENY' value.
          && mergeValues.indexOf(ch) < 0 // Not repeat.
          ) {
        mergeValues += ch;
      }
    }
    
    return (mergeValues);
  }
  
  /**
   * Gets the special user permission value by given stepID and trackID.
   * If none of special user, use the current user.
   * If specify the trackID, also research the dynamic permission definition.
   * 
   * <p>
   * Relates with {@link WorkflowProgressDAObject.getPendingProgressIDs2Display4CurrentUser(Integer)}
   * and {@link WorkflowRecordDAObject.getWorkflowIDs2Display4CurrentUser()}.
   * 
   * NOTE:<code>WorkflowRecordDAObject</code> ignore special dynamic user such as 'k' 'V' etc.
   * </p>
   * 
   * <pre>
   * Permission priority hierarchy
   * 
   * 1. User
   * 2. Special users with deny permission (submiter\submiter supervisor\previous actor\previous actor supervisor\other preview task actor\other preview task actor supervisor)
   * 3. Special users with allow permission (submiter\submiter supervisor\previous actor\previous actor supervisor\other preview task actor\other preview task actor supervisor)
   * 4. Roles with deny permission (roleA and roleB etc)
   * 5. Roles with allow permission (roleC and roleD etc)
   * 6. Groups with deny permission (groupA and groupB etc)
   * 7. Groups with allow permission (groupC and groupD etc)
   * 8. Every one
   * 
   * In the condition there are repeat definition in same priority level, 'DENY' permission is priority.
   * </pre>
   * 
   * <p>
   * <b>Permission Inheritance</b>
   * 
   * <p>
   * The inherited permission for current account, is equal to the first
   * non-null permission in the object hierarchy, starting at user and
   * proceeding upwards in the hierarchy towards the root permission. 
   * Below are four tables with various assigned permission values and the
   * resulting inherited permission according to the above rule.
   * <p>
   * Current account is User A and Role A and Role B and Group A.
   * 
   * <p>Example 1</p>
   * 
   * <table border=1>
   * <tr><td>Object              </td><td>Assigned Permission of Workflow Record A</td></tr>
   * <tr><td>Every one           </td><td>Allow                                        </td></tr>
   * <tr><td>Group A             </td><td>none                                         </td></tr>
   * <tr><td>Role A              </td><td>none                                         </td></tr>
   * <tr><td>Special user A      </td><td>none                                         </td></tr>
   * <tr><td>User A              </td><td>none                                         </td></tr>
   * <tr><td>Inherited Permission</td><td>Allow                                        </td></tr>
   * </table>
   * 
   * <p>
   * In example 1 above, only the root object is assigned a permission. This permission 
   * value, of <code>User A</code>, inherite from the root object <code>Every one</code>.
   * 
   * <p>Example 2</p>
   * <table border=1>
   * <tr><td>Object              </td><td>Assigned Permission of Workflow Record A</td></tr>
   * <tr><td>Every one           </td><td>Allow                                        </td></tr>
   * <tr><td>Group A             </td><td>none                                         </td></tr>
   * <tr><td>Role A              </td><td>none                                         </td></tr>
   * <tr><td>Special user A      </td><td>none                                         </td></tr>
   * <tr><td>User A              </td><td>Deny                                         </td></tr>
   * <tr><td>Inherited Permission</td><td>Deny                                         </td></tr>
   * </table>
   * 
   * <p>
   * In example 2, <code>User A</code> have an assigned permission value.
   * There is no need for permission inheritence.
   * 
   * <p>Example 3</p>
   * <table border=1>
   * <tr><td>Object              </td><td>Assigned Permission of Workflow Record A</td></tr>
   * <tr><td>Every one           </td><td>Allow                                        </td></tr>
   * <tr><td>Group A             </td><td>none                                         </td></tr>
   * <tr><td>Role A              </td><td>Allow                                        </td></tr>
   * <tr><td>Special user A      </td><td>none                                         </td></tr>
   * <tr><td>User A              </td><td>none                                         </td></tr>
   * <tr><td>Inherited Permission</td><td>Allow                                        </td></tr>
   * </table>
   * 
   * <p>
   * In example 3, the <code>User A</code>'s permission is none,
   * but <code>Role A</code> have an assigned permission value,
   * so inherite permission value from <code>Role A</code>. 
   * 
   * <p>Example 4</p>
   * <table border=1>
   * <tr><td>Object              </td><td>Assigned Permission of Workflow Record A</td></tr>
   * <tr><td>Every one           </td><td>Allow                                        </td></tr>
   * <tr><td>Group A             </td><td>none                                         </td></tr>
   * <tr><td>Role A              </td><td>Allow                                        </td></tr>
   * <tr><td>Role B              </td><td>Deny                                         </td></tr>
   * <tr><td>Special user A      </td><td>none                                         </td></tr>
   * <tr><td>User A              </td><td>none                                         </td></tr>
   * <tr><td>Inherited Permission</td><td>Deny                                         </td></tr>
   * </table>
   * 
   * <p>
   * In example 4, the <code>User A</code>'s permission is none,
   * but <code>Role A</code> and <code>Role B</code> all have an assigned permission value,
   * 'DENY' permission is priority, so inherite permission from <code>Role B</code>.
   * 
   * <code>NullPointerException</code> will be throw out if stepID is null.
   * 
   * @param stepID the step ID of task
   * @param trackID track ID of task
   * @param userRecordID special user
   * @return user permission value in a text format, a empty string or null value
   *         will be return if none of permission info found.
   * @throws ApplicationException application exception.
   * @throws NullPointerException if the stepID is null.
   */
  public String getUserPermission4SpecialTask(Integer stepID, Integer trackID, Integer userRecordID) throws ApplicationException {
    
    if (stepID == null) {
      throw new NullPointerException("The stepID is necessary!");
    }
    
    // Use current user if the given user is null.
    if (userRecordID == null) {
      userRecordID = sessionContainer.getUserRecordID();
    }
    
    // Get role list and group list of current user.
    MtmUserRecordUserGroupDAObject userRecordUserGroupDAO = new MtmUserRecordUserGroupDAObject(sessionContainer, dbConn);
    MtmUserRecordUserRoleDAObject userRecordUserRoleDAO = new MtmUserRecordUserRoleDAObject(sessionContainer, dbConn);
    List currentUserRoleList = userRecordUserRoleDAO.getUserRoleListByUserRecordID(userRecordID);
    List currentUserGroupList = userRecordUserGroupDAO.getUserGroupListByUserRecordID(userRecordID);
    
    WorkflowProgressDAObject progressDAO = new WorkflowProgressDAObject(sessionContainer, dbConn);
    WorkflowProgressManager progressManager = new WorkflowProgressManager(sessionContainer, dbConn);
    
    // Condition 1 : sub flow of interrupt flow, the submit step use the interrupt permission definition.
    // If the actor list of interrupt permission definition contain current user return 'READ' permission value.
    // No permission priority in this condition.
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    if (trackID != null) {
      WorkflowRecordDAObject recordDAO = new WorkflowRecordDAObject(sessionContainer, dbConn);
      WorkflowRecord workflowRecord = (WorkflowRecord) recordDAO.getObjectByTrackID(trackID);
      
      // Is sub flow of interrupt flow, continue if true.
      if (SystemWorkflowConstant.SUB_WORKFLOW_INTERRUPT.equals(workflowRecord.getWorkflowCategoryID().toString())) {
        WorkflowStepDAObject stepDAO = new WorkflowStepDAObject(sessionContainer, dbConn);
        WorkflowStep workflowStep = (WorkflowStep) stepDAO.getObjectByID(stepID);
        
        if (WorkflowStep.ACTION_TYPE_SUBMIT.equals(workflowStep.getActionType())) {
          MtmWorkflowChildParentProgressDAObject childParentProgressDAO = new MtmWorkflowChildParentProgressDAObject(sessionContainer, dbConn);
          MtmWorkflowChildParentProgress childParentProgress = (MtmWorkflowChildParentProgress) childParentProgressDAO.getListByTrackID(trackID).get(0) ; 
          WorkflowProgress parentProgress = (WorkflowProgress)progressDAO.getObjectByID(childParentProgress.getParentWorkflowProgressID());
          WorkflowRecord parentRecord = (WorkflowRecord)recordDAO.getObjectByTrackID(parentProgress.getTrackID());
          List interruptActorIDList = progressManager.getInterruptActorIDListByProgressIDAndRecordID(parentProgress, parentRecord.getID());
          
          if (Utility.isEmpty(interruptActorIDList)) {
            return ("");
          }
          
          for (int i = 0; i < interruptActorIDList.size(); i++) {
            Integer userActorID = (Integer) interruptActorIDList.get(i);
            if(userRecordID.equals(userActorID)){  
              return (READ_PERMISSION);
            }
          }
        }
      }
    }
    
    MtmWorkflowStepUserActorDAObject stepActorDAO = new MtmWorkflowStepUserActorDAObject(sessionContainer, dbConn);

    List stepUserActorList = stepActorDAO.getListByWorkflowStepID(stepID);
    
    // If the permission of given step is empty, return an empty string.
    if (Utility.isEmpty(stepUserActorList)) {
      return ("");
    }
    
    String permissionValues4User = null;
    boolean inheritDefault = false;
    String permissionValues4SpecialUser = null;
    boolean inheritFromSpecialUser = false;
    String permissionValues4UserRole = null;
    boolean inheritFromRole = false;
    String permissionValues4UserGroup = null;
    boolean inheritFromGroup = false;
    String permissionValues4Everyone = null;
    boolean inheritFromEveryone = false;
     
    // Check permission is assigned at run time.
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    boolean isAssignedStep = false;
    
    for (int i = 0; i < stepUserActorList.size(); i++) {
      MtmWorkflowStepUserActor stepUserActor = (MtmWorkflowStepUserActor)stepUserActorList.get(i);
      if (MtmWorkflowStepUserActor.ACTOR_TYPE_RUNTIME_ASSIGN.equals(stepUserActor.getActorType())) {
        isAssignedStep = true;
        break;
      }
    }
    
    // Condition 2 : permission is assigned at run time.
    // Dynamic user assigned at run time not contain special user such as 'K' 'V' 'Every one' etc!
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    if (isAssignedStep) {
      
      if (trackID == null) {
        return (""); // Track id is necessary for assigned step's permission.
      }

      List allProgressList = progressDAO.getListByStepIDAndTrackID(stepID, trackID);
      
      if (Utility.isEmpty(allProgressList)) {
        return (""); // Vist a null progress, throw out exception?
      }
      
      WorkflowProgress currentProgress = (WorkflowProgress)allProgressList.get(allProgressList.size()-1);
      
      MtmWorkflowDynamicUserActorDAObject dynamicUserDAO = new MtmWorkflowDynamicUserActorDAObject(sessionContainer, dbConn);
      List dynamicUserList = dynamicUserDAO.getListByWorkflowProgressID(currentProgress.getID());
      
      if (Utility.isEmpty(dynamicUserList)) {
        return ("");
      }
      
      for (int i = 0; i < dynamicUserList.size(); i++) {
        MtmWorkflowDynamicUserActor dynamicUserActor = (MtmWorkflowDynamicUserActor)dynamicUserList.get(i);
        
        if (GlobalConstant.SUBJECT_TYPE_USER.equals(dynamicUserActor.getActorType())) {
          if (userRecordID.equals(dynamicUserActor.getActorID())) {
            inheritFromGroup = false;
            inheritFromRole = false;
            inheritDefault = true;
            
            // Use method mergePermissionValue(target, source) deal with repeat permission definitions,
            // 'DENY' is priority.
            permissionValues4User = this.mergePermissionValue(permissionValues4User, dynamicUserActor.getPermission());
            break;
          }
        }
        
        if (!inheritDefault && GlobalConstant.SUBJECT_TYPE_ROLE.equals(dynamicUserActor.getActorType())) {
          for (int r = 0; r < currentUserRoleList.size(); r++) {
            UserRole userRole = (UserRole) currentUserRoleList.get(r);
            if (dynamicUserActor.getActorID().equals(userRole.getID())) {
              inheritFromGroup = false;
              inheritFromRole = true;
              permissionValues4UserRole = this.mergePermissionValue(permissionValues4UserRole, dynamicUserActor.getPermission());
              break;
            }
          }
        }
        
        if (!inheritDefault && !inheritFromRole && GlobalConstant.SUBJECT_TYPE_GROUP.equals(dynamicUserActor.getActorType())) {
          for (int g = 0; g < currentUserGroupList.size(); g++) {
            UserGroup userGroup = (UserGroup) currentUserGroupList.get(g);
            if (dynamicUserActor.getActorID().equals(userGroup.getID())) {
              inheritFromGroup = true;
              permissionValues4UserGroup = this.mergePermissionValue(permissionValues4UserGroup, dynamicUserActor.getPermission());
              break;
            }
          }
        }
      }
    }

    // Condition 3 : permission is not assigned at run time.
    // Research the dynamic permission when actor is 'K' 'V' etc just when trackID is not null.
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    if (!isAssignedStep) {
      for (int i = 0; i < stepUserActorList.size(); i++) {
        MtmWorkflowStepUserActor stepUserActor = (MtmWorkflowStepUserActor)stepUserActorList.get(i);
        
        // Type of user.
        if (GlobalConstant.SUBJECT_TYPE_USER.equals(stepUserActor.getActorType())) {
          if (userRecordID.equals(stepUserActor.getActorID())) {   
            inheritFromEveryone = false;
            inheritFromGroup = false;
            inheritFromRole = false;
            inheritFromSpecialUser = false;
            inheritDefault = true;
            permissionValues4User = this.mergePermissionValue(permissionValues4User, stepUserActor.getPermission());
          }
        }
        
        // Sepcial dynamic user such as 'K' 'V' etc.
        boolean isSpecialDynamicType = !GlobalConstant.SUBJECT_TYPE_USER.equals(stepUserActor.getActorType())
        && !GlobalConstant.SUBJECT_TYPE_GROUP.equals(stepUserActor.getActorType())
        && !GlobalConstant.SUBJECT_TYPE_ROLE.equals(stepUserActor.getActorType())
        && !MtmWorkflowStepUserActor.ACTOR_TYPE_EVERYONE.equals(stepUserActor.getActorType());
        
        if (!inheritDefault && isSpecialDynamicType) {
          if (trackID == null) {
            continue; // trackID is necessary, ignore or should we throw out exception?
          }
          
          List dynamicSpecialUserList = null;
          if (MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER.equals(stepUserActor.getActorType()) ||
              MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER.equals(stepUserActor.getActorType())) {
            dynamicSpecialUserList = progressManager.getActorIDListByProgressIDAndRecordID(stepUserActor.getActorType(), stepID, trackID);
          } else {
            dynamicSpecialUserList = progressManager.getActorIDListByProgressIDAndRecordID(stepUserActor.getActorType(), stepUserActor.getActorID(), trackID);
          }
          
          if (Utility.isEmpty(dynamicSpecialUserList)) {
            continue;
          }
          
          for (int u = 0; u < dynamicSpecialUserList.size(); u++) {
            if (userRecordID.equals(dynamicSpecialUserList.get(u))) {
              inheritFromEveryone = false;
              inheritFromGroup = false;
              inheritFromRole = false;
              inheritFromSpecialUser = true;
              permissionValues4SpecialUser = this.mergePermissionValue(permissionValues4SpecialUser, stepUserActor.getPermission());
            }
          }
        }
        
        // Type of role.
        if (!inheritDefault && !inheritFromSpecialUser && GlobalConstant.SUBJECT_TYPE_ROLE.equals(stepUserActor.getActorType())) {
          for (int r = 0; r < currentUserRoleList.size(); r++) {
            UserRole userRole = (UserRole) currentUserRoleList.get(r);
            if (stepUserActor.getActorID().equals(userRole.getID())) {
              
              inheritFromEveryone = false;
              inheritFromGroup = false;
              inheritFromRole = true;
              permissionValues4UserRole = this.mergePermissionValue(permissionValues4UserRole, stepUserActor.getPermission());
              break;
            }
          }
        }
        
        // Type of group.
        if (!inheritDefault && !inheritFromSpecialUser && !inheritFromRole && GlobalConstant.SUBJECT_TYPE_GROUP.equals(stepUserActor.getActorType())) {
          for (int g = 0; g < currentUserGroupList.size(); g++) {
            UserGroup userGroup = (UserGroup) currentUserGroupList.get(g);
            if (stepUserActor.getActorID().equals(userGroup.getID())) {
              inheritFromEveryone = false;
              inheritFromGroup = true;
              permissionValues4UserGroup = this.mergePermissionValue(permissionValues4UserGroup, stepUserActor.getPermission());
              break;
            }
          }
        }
        
        // Type of every one.
        if (!inheritDefault && !inheritFromSpecialUser && !inheritFromRole && !inheritFromGroup && MtmWorkflowStepUserActor.ACTOR_TYPE_EVERYONE.equals(stepUserActor.getActorType())) {
          inheritFromEveryone = true;
          permissionValues4Everyone = this.mergePermissionValue(permissionValues4Everyone, stepUserActor.getPermission());
        }
      }
    }
    
    // Return by the priority.
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    if (inheritDefault && permissionValues4User != null) {
      return (permissionValues4User);
    }
    
    if (inheritFromSpecialUser && permissionValues4SpecialUser != null) {
      return (permissionValues4SpecialUser);
    }
    
    if (inheritFromRole && permissionValues4UserRole != null) {
      return (permissionValues4UserRole);
    }
    
    if (inheritFromGroup && permissionValues4UserGroup != null) {
      return (permissionValues4UserGroup);
    }
    
    if (inheritFromEveryone && permissionValues4Everyone != null) {
      return (permissionValues4Everyone);
    }
    
    return ("");
  }
  
  /**
   * Gets a string of the user permission for given workflow step,workflow track and user record
   * 
   * @param stepID The workflow step ID
   * @param trackID The workflow track ID
   * @param userRecordID The user record ID
   * @return string of the user permission
   * @throws ApplicationException
   * 
   * @deprecated
   */
  public String getPermissionForUser(Integer stepID, Integer trackID, Integer userRecordID)throws ApplicationException {
    MtmWorkflowStepUserActorDAObject stepActorDAO = new MtmWorkflowStepUserActorDAObject(sessionContainer, dbConn);
    MtmUserRecordUserGroupDAObject userRecordUserGroupDAO = new MtmUserRecordUserGroupDAObject(sessionContainer, dbConn);
    MtmUserRecordUserRoleDAObject userRecordUserRoleDAO = new MtmUserRecordUserRoleDAObject(sessionContainer, dbConn);
    MtmWorkflowChildParentProgressDAObject childParentProgressDAO = new MtmWorkflowChildParentProgressDAObject(sessionContainer, dbConn);
    
    WorkflowProgressDAObject progressDAO = new WorkflowProgressDAObject(sessionContainer, dbConn);
    WorkflowRecordDAObject recordDAO = new WorkflowRecordDAObject(sessionContainer, dbConn);
    WorkflowStepDAObject stepDAO = new WorkflowStepDAObject(sessionContainer, dbConn);
    
    UserGroupDAObject groupDAO = new UserGroupDAObject(sessionContainer, dbConn);
    UserRoleDAObject roleDAO = new UserRoleDAObject(sessionContainer, dbConn);
    
    WorkflowProgressManager progressManager = new WorkflowProgressManager(sessionContainer, dbConn); 
    
    WorkflowProgress workflowProgress = null;
    WorkflowRecord workflowRecord = null;
    WorkflowStep workflowStep = null;
    MtmWorkflowChildParentProgress childParentProgress = null;
    
    MtmWorkflowDynamicUserActorDAObject dynamicUserDAO = new MtmWorkflowDynamicUserActorDAObject(sessionContainer, dbConn);
    
    String userPermission = new String("");
    String isAssignOwner = "N";
    
    // if is get current user permission for step;
    if (Utility.isEmpty(userRecordID)) {
      userRecordID = sessionContainer.getUserRecordID();
    }
    
    List stepUserActorList = stepActorDAO.getListByWorkflowStepID(stepID);
    for (int i = 0; !Utility.isEmpty(stepUserActorList) && i < stepUserActorList.size(); i++) {
    	 MtmWorkflowStepUserActor stepUserActor = (MtmWorkflowStepUserActor)stepUserActorList.get(i);
    	if (MtmWorkflowStepUserActor.ACTOR_TYPE_RUNTIME_ASSIGN.equals(stepUserActor.getActorType())) {
    		isAssignOwner = "Y";
    		break;
    	}
    }
    
    if (!Utility.isEmpty(stepUserActorList) && "N".equals(isAssignOwner)) {
      // where stepUserActorList has current user  ==>get permissionTypes form this;
      for (int i = 0; i < stepUserActorList.size(); i++) {
        MtmWorkflowStepUserActor stepUserActor = (MtmWorkflowStepUserActor)stepUserActorList.get(i);
        if (GlobalConstant.SUBJECT_TYPE_USER.equals(stepUserActor.getActorType())) {
          if (stepUserActor.getActorID().equals(userRecordID)) {
            userPermission = stepUserActor.getPermission();
            break;
          }
        }
      }
      
      for (int i = 0; !Utility.isEmpty(trackID) && i < stepUserActorList.size(); i++) {
        // when userPermission is null ,priority get permissionTypes from in particuar Type
        MtmWorkflowStepUserActor stepUserActor = (MtmWorkflowStepUserActor)stepUserActorList.get(i);
        if (!GlobalConstant.SUBJECT_TYPE_USER.equals(stepUserActor.getActorType()) && 
            !GlobalConstant.SUBJECT_TYPE_GROUP.equals(stepUserActor.getActorType()) &&
            !GlobalConstant.SUBJECT_TYPE_ROLE.equals(stepUserActor.getActorType())) {
          
          List userRecordList = null;
          if (MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER.equals(stepUserActor.getActorType()) ||
              MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER.equals(stepUserActor.getActorType())) {
            userRecordList = progressManager.getActorIDListByProgressIDAndRecordID(stepUserActor.getActorType(), stepID, trackID);
          } else {
            userRecordList = progressManager.getActorIDListByProgressIDAndRecordID(stepUserActor.getActorType(), stepUserActor.getActorID(), trackID);
          }
          if (!Utility.isEmpty(userRecordList)) {
            for( int j = 0; j < userRecordList.size(); j++) {
              //this method check the permission of current userRecord which specify,so can not use sessionContainer...
              //if (this.sessionContainer.getUserRecordID().equals((Integer)userRecordList.get(j))) {
                if(userRecordID.equals((Integer)userRecordList.get(j))){
                  String currentPermission = stepUserActor.getPermission();
                  for (int h = 0; !Utility.isEmpty(currentPermission) && h < currentPermission.length(); h++) {
                    if (userPermission.indexOf(currentPermission.charAt(h)) < 0) {
                      userPermission += currentPermission.charAt(h);
                    }
                  }
                  break;
                }
            }
          }
        }
      }
      
      List groupList = userRecordUserGroupDAO.getUserGroupListByUserRecordID(userRecordID) ;
      for (int i = 0; i < stepUserActorList.size(); i++) {
        MtmWorkflowStepUserActor stepUserActor = (MtmWorkflowStepUserActor)stepUserActorList.get(i);
        if (GlobalConstant.SUBJECT_TYPE_GROUP.equals(stepUserActor.getActorType())) {
          for (int j = 0; j < groupList.size(); j++ ) {
            UserGroup userGroup = (UserGroup)groupList.get(j);
            if (stepUserActor.getActorID().equals(userGroup.getID())) {
              String currentPermission = stepUserActor.getPermission();
              for (int h = 0; !Utility.isEmpty(currentPermission) && h < currentPermission.length(); h++) {
                if (userPermission.indexOf(currentPermission.charAt(h)) < 0) {
                  userPermission += currentPermission.charAt(h);
                }
              }
            }
          }
        }
      }
      List roleList = userRecordUserRoleDAO.getUserRoleListByUserRecordID(userRecordID) ;
      for (int i = 0;  i < stepUserActorList.size(); i++) {
        MtmWorkflowStepUserActor stepUserActor = (MtmWorkflowStepUserActor)stepUserActorList.get(i);
        if (GlobalConstant.SUBJECT_TYPE_ROLE.equals(stepUserActor.getActorType())) {
          for (int j = 0; j < roleList.size(); j++ ) {
            UserRole userRole = (UserRole)roleList.get(j);
            if (stepUserActor.getActorID().equals(userRole.getID())) {
              String currentPermission = stepUserActor.getPermission();
              for (int h = 0; !Utility.isEmpty(currentPermission) && h < currentPermission.length(); h++) {
                if (userPermission.indexOf(currentPermission.charAt(h)) < 0) {
                  userPermission += currentPermission.charAt(h);
                }
              }
            }
          }
        }
      }
//    get the Everyone Owner Type
      for (int i = 0;   i < stepUserActorList.size(); i++) {
        MtmWorkflowStepUserActor stepUserActor = (MtmWorkflowStepUserActor)stepUserActorList.get(i);
        if(MtmWorkflowStepUserActor.ACTOR_TYPE_EVERYONE.equals(stepUserActor.getActorType())){
          String currentPermission = stepUserActor.getPermission();
          for (int h = 0; !Utility.isEmpty(currentPermission) && h < currentPermission.length(); h++) {
            if (userPermission.indexOf(currentPermission.charAt(h)) < 0) {
              userPermission += currentPermission.charAt(h);
            }
          }
        }
      }  
      // TODO :the case: assign owners  
    } else if ("Y".equals(isAssignOwner)) {
    	List allProgressList = progressDAO.getListByStepIDAndTrackID(stepID, trackID);
    	if (!Utility.isEmpty(allProgressList)) {
    		WorkflowProgress currentProgress = (WorkflowProgress)allProgressList.get(allProgressList.size()-1); 
    		List dynamicUserList = dynamicUserDAO.getListByWorkflowProgressID(currentProgress.getID());
    		if (!Utility.isEmpty(dynamicUserList)) {
    			for (int i = 0; i < dynamicUserList.size(); i++) {
    				MtmWorkflowDynamicUserActor dynimicUserActor = (MtmWorkflowDynamicUserActor)dynamicUserList.get(i);
            if (GlobalConstant.SUBJECT_TYPE_USER.equals(dynimicUserActor.getActorType())) {
              if (dynimicUserActor.getActorID().equals(userRecordID)) {
                userPermission = dynimicUserActor.getPermission();
                break;
              }
            }
          }
    			
    			List groupList = userRecordUserGroupDAO.getUserGroupListByUserRecordID(userRecordID) ;
          for (int i = 0; i < dynamicUserList.size(); i++) {
          	MtmWorkflowDynamicUserActor dynimicUserActor = (MtmWorkflowDynamicUserActor)dynamicUserList.get(i);
            if (GlobalConstant.SUBJECT_TYPE_GROUP.equals(dynimicUserActor.getActorType())) {
              for (int j = 0; j < groupList.size(); j++ ) {
                UserGroup userGroup = (UserGroup)groupList.get(j);
                if (dynimicUserActor.getActorID().equals(userGroup.getID())) {
                  String currentPermission = dynimicUserActor.getPermission();
                  for (int h = 0; !Utility.isEmpty(currentPermission) && h < currentPermission.length(); h++) {
                    if (userPermission.indexOf(currentPermission.charAt(h)) < 0) {
                      userPermission += currentPermission.charAt(h);
                    }
                  }
                }
              }
            }
          }
          List roleList = userRecordUserRoleDAO.getUserRoleListByUserRecordID(userRecordID) ;
          for (int i = 0; i < dynamicUserList.size(); i++) {
          	MtmWorkflowDynamicUserActor dynimicUserActor = (MtmWorkflowDynamicUserActor)dynamicUserList.get(i);
            if (GlobalConstant.SUBJECT_TYPE_ROLE.equals(dynimicUserActor.getActorType())) {
              for (int j = 0; j < roleList.size(); j++ ) {
                UserRole userRole = (UserRole)roleList.get(j);
                if (dynimicUserActor.getActorID().equals(userRole.getID())) {
                  String currentPermission = dynimicUserActor.getPermission();
                  for (int h = 0; !Utility.isEmpty(currentPermission) && h < currentPermission.length(); h++) {
                    if (userPermission.indexOf(currentPermission.charAt(h)) < 0) {
                      userPermission += currentPermission.charAt(h);
                    }
                  }
                }
              }
            }
          }
    		} else {
    			log.debug("not Find dynamic user owner!!");
    		}
    	}
    }
    
    //Add inturrept User
    //if workrecord is a interrupt flow then found the interrupt users
    if(!Utility.isEmpty(trackID)&&!Utility.isEmpty(stepID)){
      try{
        workflowProgress = (WorkflowProgress)progressDAO.getObjectByID(progressDAO.getWorkflowProgressIDByStepIDTrackID(stepID, trackID));
      }catch(ApplicationException ex){log.info(ex);}
      if(workflowProgress!=null){
        workflowRecord = (WorkflowRecord)recordDAO.getObjectByTrackID(workflowProgress.getTrackID());

        if(workflowRecord.getWorkflowCategoryID().intValue()==Integer.parseInt(SystemWorkflowConstant.SUB_WORKFLOW_INTERRUPT)){//is interrupt flow
          //get the start step
          workflowStep = (WorkflowStep)stepDAO.getObjectByID(stepID);
          if(WorkflowStep.ACTION_TYPE_SUBMIT.equals(workflowStep.getActionType())){
            childParentProgress = (MtmWorkflowChildParentProgress)childParentProgressDAO.getListByTrackID(trackID).get(0) ; 
            WorkflowProgress parentProgress = (WorkflowProgress)progressDAO.getObjectByID(childParentProgress.getParentWorkflowProgressID());
            WorkflowRecord parentRecord = (WorkflowRecord)recordDAO.getObjectByTrackID(parentProgress.getTrackID());
            try{
              List interruptActorIDList = progressManager.getInterruptActorIDListByProgressIDAndRecordID(parentProgress, parentRecord.getID());

              for (int k = 0; !Utility.isEmpty(interruptActorIDList) && k < interruptActorIDList.size(); k++) {
                Integer userActorID = (Integer)interruptActorIDList.get(k);
                //if(this.sessionContainer.getUserRecordID().equals(userActorID)) {//TC.delete
                if(userRecordID.equals(userActorID)){  
                  userPermission+="RW";
                  break;
                }
              }
            } catch(Exception ex){log.info(ex);}
          }
        }
      }
    }
    //ADD BY TC
   // userPermission+="RW";
    log.debug("the currentUserPermission is ::::::" + userPermission);
    if (!Utility.isEmpty(userPermission)) {
      if (!userPermission.equals(userPermission.toUpperCase())) {
        String currentUserPermission = new String(userPermission);
        String noPermissionStr = ""; 
        userPermission = "";
        log.debug("the currentUserPermission is ::::::" + currentUserPermission);
        for (int i = 0; i < currentUserPermission.length(); i++) {
          if (currentUserPermission.substring(i, i+1).equals(currentUserPermission.substring(i, i+1).toUpperCase())) {
            userPermission += currentUserPermission.substring(i, i+1);
          } else {
          	noPermissionStr += currentUserPermission.substring(i, i+1);
          }
        }
        if (!Utility.isEmpty(noPermissionStr)) {
        	String curUserPermission = new String(userPermission);
        	userPermission = "";
        	for (int i = 0; i < curUserPermission.length(); i++) {
            if (noPermissionStr.indexOf(curUserPermission.substring(i, i+1).toLowerCase()) < 0) {
              userPermission += curUserPermission.substring(i, i+1);
            } 
          }
        }
      }
    }
    
    log.debug("the currentUserPermission is ::::::" + userPermission);
    return userPermission;
  }
  
}
